package com.book.oauth.server.client.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.book.common.helper.I18nHelper;
import com.book.common.util.GuavaCacheUtil;
import com.book.common.api.oauth.CacheKey;
import com.book.oauth.server.client.entity.Client;
import com.book.oauth.server.client.service.IClientService;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.stereotype.Service;

import java.util.Arrays;

/**
 * Description： 客户端详情信息，客户端详情信息在这里进行初始化，通过数据库来存储调取详情信息
 * 用户登录时（即携带参数请求/oauth/token接口）会调用这两个service。
 * 1、MyClientDetailsService是根据client_id查出来的信息验证用户登录时携带的参数（即客户端详情表信息）是否正确。并且设置能访问的资源id集合。
 * 2、MyUserDetailService是根据用户名去查用户密码，用户所拥有的角色等信息，然后丢给security去验证用户登录时的用户名和密码是否正确。
 * 以上都正确则返回token信息，并把token信息存到了token详情表，refresh_token详情表中（token存储方式为数据库）。然后就可以根据拿到的token去请求被security管理起来的接口地址。
 *
 * @Author： leo.xiong
 * @CreateDate： 2019/10/12 16:27
 * @Email： leo.xiong@suyun360.com
 * Version：1.0
 */
@Slf4j
@DS(value = "oauth")
@Service("clientDetailsServiceImpl")
public class ClientDetailsServiceImpl implements ClientDetailsService {

    @Autowired
    private IClientService clientService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private I18nHelper i18nHelper;

    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        BaseClientDetails clientDetails = GuavaCacheUtil.get(CacheKey.OAUTH_CLIENT_ENCODER, BaseClientDetails.class);
        if (clientDetails != null) {
            return clientDetails;
        }
        Client client = clientService.getClientByCacheAndDb(clientId);
        if (client == null) {
            throw new RuntimeException(i18nHelper.get("BOOK:OAUTH:10007"));
        }
        clientDetails = new BaseClientDetails();
        //客户端(client)id
        clientDetails.setClientId(client.getClientId());
        //客户端所能访问的资源id集合
        clientDetails.setResourceIds(Arrays.asList(client.getResourceIds().split(",")));
        //客户端(client)的访问密匙
        clientDetails.setClientSecret(passwordEncoder.encode(client.getClientSecret()));
        //客户端支持的grant_type授权类型
        clientDetails.setAuthorizedGrantTypes(Arrays.asList(client.getAuthorizedGrantTypes().split(",")));
        //客户端申请的权限范围
        clientDetails.setScope(Arrays.asList(client.getScope().split(",")));
        //重定向路径
        clientDetails.setRegisteredRedirectUri(Sets.newHashSet(client.getWebServerRedirectUri()));
        Integer accessTokenValidity = client.getAccessTokenValidity();
        if (accessTokenValidity != null && accessTokenValidity > 0) {
            //设置token的有效期，不设置默认12小时
            clientDetails.setAccessTokenValiditySeconds(accessTokenValidity);
        }
        Integer refreshTokenValidity = client.getRefreshTokenValidity();
        if (refreshTokenValidity != null && refreshTokenValidity > 0) {
            //设置刷新token的有效期，不设置默认30天
            clientDetails.setRefreshTokenValiditySeconds(refreshTokenValidity);
        }
        GuavaCacheUtil.put(CacheKey.OAUTH_CLIENT_ENCODER + clientId, clientDetails);
        return clientDetails;
    }
}
